﻿#建议保存编码为：bom头 + utf8


$开始 = Get-Date
$输入并发数组 = New-Object 'System.Collections.Concurrent.ConcurrentBag[object]'
foreach ($private:当前被控机3 in $global:所有被控机)
{
	$null = $输入并发数组.add($private:当前被控机3)
}

$输出并发数组 = New-Object 'System.Collections.Concurrent.ConcurrentBag[object]'

1..($global:所有被控机.count + 3) | ForEach-Object -ThrottleLimit 30 -Parallel {

	function fh返回被控机的_开放端口信息
	{
		param
		(
			[parameter(Mandatory = $true)]
			[ValidateNotNullOrEmpty()]
			[String]$目的ip地址,
			[String]$目的端口
		)

		if ($IsLinux -eq $True)
		{
			switch (${目的端口})
			{
				'22'
				{
					if (Test-Connection -TargetName $目的ip地址 -TCPPort 22 -Quiet)
					{
						& 'zkj_从主控机到linux被控机_ssh_knowhost免yes.ps1'
						$结果 = 'linux'
						return $结果
					}
					else
					{
						Write-Verbose  "错误，被控机 ${目的ip地址} 的22端口不通"
						$结果 = "被控机 ${目的ip地址} 开放端口未知"
						return $结果
					}
				}

				'135'
				{
					if (Test-Connection -TargetName $目的ip地址 -TCPPort 135 -Quiet)
					{
						$结果 = 'win135'
						return $结果
					}
					else
					{
						Write-Verbose "错误，被控机 ${目的ip地址} 的135端口不通"
						$结果 = "被控机 ${目的ip地址} 开放端口未知"
						return $结果
					}
				}

				'5985'
				{
					if (Test-Connection -TargetName $目的ip地址 -TCPPort 5985 -Quiet)
					{
						$结果 = 'win5985'
						return $结果
					}
					else
					{
						Write-Verbose "错误，被控机 ${目的ip地址} 的5985端口不通"
						$结果 = "被控机 ${目的ip地址} 开放端口未知"
						return $结果
					}
				}

				'5986'
				{
					if (Test-Connection -TargetName $目的ip地址 -TCPPort 5986 -Quiet)
					{
						$结果 = 'win5986'
						return $结果
					}
					else
					{
						Write-Verbose "错误，被控机 ${目的ip地址} 的5986端口不通"
						$结果 = "被控机 ${目的ip地址} 开放端口未知"
						return $结果
					}
				}

				Default
				{
					if ( ${目的端口} -eq '')
					{
						#扫描端口，速度较慢
						if (Test-Connection -TargetName $目的ip地址 -TCPPort 5985 -Quiet)
						{
							$结果 = 'win5985'
							return $结果
						}
						else
						{
							Write-Verbose "错误，被控机 ${目的ip地址} 的5985端口不通"
						}

						if (Test-Connection -TargetName $目的ip地址 -TCPPort 5986 -Quiet)
						{
							$结果 = 'win5986'
							return $结果
						}
						else
						{
							Write-Verbose "错误，被控机 ${目的ip地址} 的5986端口不通"
						}

						if (Test-Connection -TargetName $目的ip地址 -TCPPort 135 -Quiet)
						{
							$结果 = 'win135'
							return $结果
						}
						else
						{
							Write-Verbose "错误，被控机 ${目的ip地址} 的135端口不通"
						}

						if (Test-Connection -TargetName $目的ip地址 -TCPPort 22 -Quiet)
						{
							& 'zkj_从主控机到linux被控机_ssh_knowhost免yes.ps1'
							$结果 = 'linux'
							return $结果
						}
						else
						{
							Write-Verbose  "错误，被控机 ${目的ip地址} 的22端口不通"
						}
						Write-Verbose  "被控机 ${目的ip地址} 开放端口未知"
						$结果 = "被控机 ${目的ip地址} 开放端口未知"
						return $结果
					}
					else
					{
						if (Test-Connection -TargetName $目的ip地址 -TCPPort $目的端口 -Quiet)
						{
							Write-Verbose  "被控机 ${目的ip地址} 端口 $目的端口 通了"
							$结果 = "被控机 ${目的ip地址} 端口 $目的端口 通了"
							return $结果
						}
						else
						{
							Write-Verbose  "被控机 ${目的ip地址} 开放端口未知"
							$结果 = "被控机 ${目的ip地址} 开放端口未知"
							return $结果
						}
					}
				}
			}
		}


		if ( ($IsWindows -eq $True) -or ($PSVersionTable.psversion.major -lt 6) ) #win
		{
			switch (${目的端口})
			{
				'5985'
				{
					if (& 'tcp--ping-v2.ps1' $目的ip地址 5985 -Quiet)
					{
						$结果 = 'win5985'
						return $结果
					}
					else
					{
						Write-Verbose  "错误，被控机 ${目的ip地址} 的5985端口不通"
						$结果 = "被控机 ${目的ip地址} 开放端口未知"
						return $结果
					}
				}

				'5986'
				{
					if (& 'tcp--ping-v2.ps1' $目的ip地址 5986 -Quiet)
					{
						$结果 = 'win5986'
						return $结果
					}
					else
					{
						Write-Verbose  "错误，被控机 ${目的ip地址} 的5986端口不通"
						$结果 = "被控机 ${目的ip地址} 开放端口未知"
						return $结果
					}
				}

				'135'
				{
					if (& 'tcp--ping-v2.ps1' $目的ip地址 135 -Quiet)
					{
						$结果 = 'win135'
						return $结果
					}
					else
					{
						Write-Verbose  "错误，被控机 ${目的ip地址} 的135端口不通"
						$结果 = "被控机 ${目的ip地址} 开放端口未知"
						return $结果
					}
				}

				'22'
				{
					if (& 'tcp--ping-v2.ps1' $目的ip地址 22 -Quiet)
					{
						& 'zkj_从主控机到linux被控机_ssh_knowhost免yes.ps1'
						$结果 = 'linux'
						return $结果
					}
					else
					{
						Write-Verbose  "错误，被控机 ${目的ip地址} 的22端口不通"
						$结果 = "被控机 ${目的ip地址} 开放端口未知"
						return $结果
					}
				}

				Default
				{
					if ( ${目的端口} -eq '')
					{
						#扫描端口，速度较慢
						if (& 'tcp--ping-v2.ps1' $目的ip地址 5985 -Quiet)
						{
							$结果 = 'win5985'
							return $结果
						}
						else
						{
							Write-Verbose  "错误，被控机 ${目的ip地址} 的5985端口不通"
						}

						if (& 'tcp--ping-v2.ps1' $目的ip地址 5986 -Quiet)
						{
							$结果 = 'win5986'
							return $结果
						}
						else
						{
							Write-Verbose  "错误，被控机 ${目的ip地址} 的5986端口不通"
						}

						if (& 'tcp--ping-v2.ps1' $目的ip地址 135 -Quiet)
						{
							$结果 = 'win135'
							return $结果
						}
						else
						{
							Write-Verbose  "错误，被控机 ${目的ip地址} 的135端口不通"
						}

						if (& 'tcp--ping-v2.ps1' $目的ip地址 22 -Quiet)
						{
							& 'zkj_从主控机到linux被控机_ssh_knowhost免yes.ps1'
							$结果 = 'linux'
							return $结果
						}
						else
						{
							Write-Verbose  "错误，被控机 ${目的ip地址} 的22端口不通"
						}
						Write-Verbose  "被控机 ${目的ip地址} 开放端口未知"
						$结果 = "被控机 ${目的ip地址} 开放端口未知"
						return $结果
					}
					else
					{
						if (& 'tcp--ping-v2.ps1' $目的ip地址 $目的端口 -Quiet)
						{
							Write-Verbose  "被控机 ${目的ip地址} 端口 $目的端口 通了"
							$结果 = "被控机 ${目的ip地址} 端口 $目的端口 通了"
							return $结果
						}
						else
						{
							Write-Verbose  "被控机 ${目的ip地址} 开放端口未知"
							$结果 = "被控机 ${目的ip地址} 开放端口未知"
							return $结果
						}
					}
				}
			}
		}

	}

	function 写输出并发数组
	{
		param
		(
			$输出对象,
			[String]$被控机os关键字2
		)

		Write-Host ("被控机【{0}】的os类型是:【{1}】" -f $输出对象.被控机显示名,$被控机os关键字2 )
		$输出对象.被控机os类型 = $被控机os关键字2
		$输出并发数组2 = $using:输出并发数组
		$输出并发数组2.add($输出对象)
	}

	#region main2
	$输入并发数组2 = $using:输入并发数组
	if ($输入并发数组2.Count -gt 0)
	{
		for ($private:iii = 1;$private:iii -lt 21;$private:iii++)
		{
			$private:值 = $null
			if ($输入并发数组2.TryTake([ref]$private:值))
			{
				break
			}
			Start-Sleep -Milliseconds 67
		}

		[System.Net.IPAddress]$ip2 = 0
		if (   [System.Net.IPAddress]::TryParse($private:值.ip,[ref]$ip2)      )
		{
			[string]$private:被控机的端口信息是 = fh返回被控机的_开放端口信息 -目的ip地址 $private:值.ip -目的端口 $private:值.端口
			Write-Host ("被控机【{0}】的端口关键字是：【{1}】" -f $private:值.被控机显示名,${private:被控机的端口信息是} )

			if ( $private:被控机的端口信息是.Contains('未知') -or $private:被控机的端口信息是.Contains('不通') )
			{
				$private:被控机os关键字 = '【被控机】开放端口未知！'
				写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
			}

			if ( $private:被控机的端口信息是.Contains('通了') )
			{
				$private:被控机os关键字 = '自定义端口，请联系开发者'
				写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
			}

			$private:linux版本字串 = 'centos8','centos7','centos6','debian8','debian9','debian10','ubuntu1404','ubuntu1604','ubuntu1804','centos8','alpine'

			[scriptblock]$private:判断linux发行版 =
			{
				if (Select-String -Pattern 'centos-8' -Path '/etc/*-release' -SimpleMatch -Quiet)
				{
					return 'centos8'
				}

				if (Select-String -Pattern 'centos-7' -Path '/etc/*-release' -SimpleMatch -Quiet)
				{
					return 'centos7'
				}

				if (Select-String -Pattern 'centos' -Path '/etc/*-release' -SimpleMatch -Quiet)
				{
					return 'centos6'
				}

				if (Select-String -Pattern 'jessie' -Path '/etc/*-release' -SimpleMatch -Quiet)
				{
					return 'debian8'
				}

				if (Select-String -Pattern 'stretch' -Path '/etc/*-release' -SimpleMatch -Quiet)
				{
					return 'debian9'
				}

				if (Select-String -Pattern 'buster' -Path '/etc/*-release' -SimpleMatch -Quiet)
				{
					return 'debian10'
				}

				if (Select-String -Pattern 'Trusty Tahr' -Path '/etc/*-release' -SimpleMatch -Quiet)
				{
					return 'ubuntu1404'
				}

				if (Select-String -Pattern 'Xenial Xerus' -Path '/etc/*-release' -SimpleMatch -Quiet)
				{
					return 'ubuntu1604'
				}

				if (Select-String -Pattern 'Bionic Beaver' -Path '/etc/*-release' -SimpleMatch -Quiet)
				{
					return 'ubuntu1804'
				}

				if (Select-String -Pattern 'Alpine' -Path '/etc/*-release' -SimpleMatch -Quiet)
				{
					return 'Alpine'
				}
			}

			$private:win版本字串 = 'win2008r2','win7','win8','win10','win2012r2','win2016','win2019'

			[scriptblock]$private:判断win版本 =
			{
				if ( (Get-WmiObject -Class Win32_OperatingSystem).Caption -like "*2008r2*" )
				{
					return 'win2008r2'
				}

				if ( (Get-WmiObject -Class Win32_OperatingSystem).Caption -like "*7*" )
				{
					return 'win7'
				}

				if ( (Get-WmiObject -Class Win32_OperatingSystem).Caption -like "*8*" )
				{
					return 'win8'
				}

				if ( (Get-WmiObject -Class Win32_OperatingSystem).Caption -like "*10*" )
				{
					return 'win10'
				}

				if ( (Get-WmiObject -Class Win32_OperatingSystem).Caption -like "*2012 r2*" )
				{
					return 'win2012r2'
				}

				if ( (Get-WmiObject -Class Win32_OperatingSystem).Caption -like "*2016*" )
				{
					return 'win2016'
				}

				if ( (Get-WmiObject -Class Win32_OperatingSystem).Caption -like "*2019*" )
				{
					return 'win2019'
				}
			}


			if ($IsLinux -eq $True)
			{
				if ( ($private:被控机的端口信息是 -eq 'win5985') -or ($private:被控机的端口信息是 -eq 'win5986') )
				{
					$private:被控机os关键字 = "从linux【主控机】中，经winrm协议，控制win【被控机】，无法实现！"
					写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
				}

				if ($private:被控机的端口信息是 -eq 'win135')
				{
					$private:被控机os关键字 = "从linux【主控机】中，经wmic协议+135端口，控制win【被控机】，无法实现！"
					写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
				}

				if ($private:被控机的端口信息是 -eq 'linux')
				{
					$l2l = & 'run_linux2linux_key_pwd.ps1' -目的ip地址 $private:值.ip -powershell代码块 $private:判断linux发行版
					if ($l2l -in $private:linux版本字串)
					{
						$private:被控机os关键字 = $l2l
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
					elseif ($l2l[-1] -in $private:linux版本字串)
					{
						$private:被控机os关键字 = $l2l[-1]
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
					else
					{
						$private:被控机os关键字 = '【被控机】linux发行版未知'
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
				}
			}

			if ( ($IsWindows -eq $True) -or ($PSVersionTable.psversion.major -lt 6) ) #win
			{
				if ($private:被控机的端口信息是 -eq 'win5985')
				{
					$w2w = & 'run_win2win5985_pwd.ps1' -目的ip地址 $private:值.ip -powershell代码块 $private:判断win版本
					if ($w2w -in $private:win版本字串)
					{
						$private:被控机os关键字 = $w2w
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
					elseif ($w2w[-1] -in $private:win版本字串)
					{
						$private:被控机os关键字 = $w2w[-1]
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
					else
					{
						$private:被控机os关键字 = '【被控机】win版本未知'
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
				}

				if ($private:被控机的端口信息是 -eq 'win5986')
				{
					$w2w = & 'run_win2win5986_pwd.ps1' -目的ip地址 $private:值.ip -端口 5986 -powershell代码块 $private:判断win版本
					if ($w2w -in $private:win版本字串)
					{
						$private:被控机os关键字 = $w2w
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
					elseif ($w2w[-1] -in $private:win版本字串)
					{
						$private:被控机os关键字 = $w2w[-1]
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
					else
					{
						$private:被控机os关键字 = '【被控机】win版本未知'
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
				}

				if ($private:被控机的端口信息是 -eq 'win135')
				{
					$private:被控机os关键字 = "从win【主控机】中，经wmic协议+135端口，控制win【被控机】，无法实现！"
					写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
				}

				if ($private:被控机的端口信息是 -eq 'linux')
				{
					$w2l = & 'run_win2linux_key_pwd.ps1' -目的ip地址 $private:值.ip -powershell代码块 $private:判断linux发行版
					if ($w2l -in $private:linux版本字串)
					{
						$private:被控机os关键字 = $w2l
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
					elseif ($w2l[-1] -in $private:linux版本字串)
					{
						$private:被控机os关键字 = $w2l[-1]
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
					else
					{
						$private:被控机os关键字 = '【被控机】linux发行版未知'
						写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
					}
				}
			}
		}
		else
		{
			Write-Error "nodelist文件中找到这个ip地址： $($当前被控机.ip)，但ip不合法"
			$private:被控机os关键字 = '非法ip地址'
			写输出并发数组 -输出对象 $private:值 -被控机os关键字2 $private:被控机os关键字
		}

	}
	#endregion main2


}

#写输出
$private:被控机的_os关键字_已经处理完成数 = 0
while ($global:所有被控机.count -gt $private:被控机的_os关键字_已经处理完成数)
{
	Start-Sleep -Seconds 1
	$秒++
	if ($秒 -gt 10)
	{
		Write-Error '错误：刷新被控机os类型，等待时间太长。刷新失败。错误码21'
		$private:被控机的_os关键字_已经处理完成数
		exit 21
	}

	while ($输出并发数组.Count -gt 0)
	{
		$private:值2 = $null
		if ($输出并发数组.TryTake([ref]$private:值2))
		{
			$private:当前被控机 = $global:所有被控机 | Where-Object { $_.ip -eq $private:值2.ip }
			Add-Member -InputObject ${private:当前被控机} -MemberType NoteProperty -Name '被控机os类型' -Value $private:值2.被控机os类型 -Force
			$private:被控机的_os关键字_已经处理完成数++
		}
	}
	Write-Verbose "写耗时【$秒】秒，处理完了【$private:被控机的_os关键字_已经处理完成数】"
}
$结束 = Get-Date
$总耗时 = ($结束 - $开始).Seconds
Write-Verbose "总耗时【$总耗时】秒"
exit 0

